﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Glue.Internals
{
    internal class AutoRelater<LeftType, RightType> : IAutoRelateResult<LeftType, RightType>
    {
        private readonly RelationFactory relationFactory;
        private readonly RelationContainer<LeftType, RightType> relations;
        private readonly MemberContainer ignoredMembers;
        private readonly bool includeFields;
        private readonly bool caseInsensitive;
        private readonly ObjectMemberFactory objectMemberFactory;

        public AutoRelater(RelationFactory relationFactory, RelationContainer<LeftType, RightType> relations, 
            MemberContainer ignoredMembers, bool includeFields, bool caseInsensitive, ObjectMemberFactory objectMemberFactory)
        {
            this.relationFactory = relationFactory;
            this.relations = relations;
            this.objectMemberFactory = objectMemberFactory;
            this.ignoredMembers = ignoredMembers;
            this.includeFields = includeFields;
            this.caseInsensitive = caseInsensitive;
        }

        public void AutoRelateEqualNames()
        {
            var leftProperties = objectMemberFactory.GetObjectMembers(typeof(LeftType),includeFields);
            var rightProperties = GetMemberDictionary();
            foreach (var leftProperty in leftProperties)
            {
                var leftPropertyName = GetMemberName(leftProperty);
                if (!rightProperties.ContainsKey(leftPropertyName)) continue;
                var rightProperty = rightProperties[leftPropertyName];

                var maybeRelation = relationFactory.TryCreate(leftProperty, rightProperty, ignoredMembers.ContainsLeftSide(leftProperty), ignoredMembers.ContainsRightSide(rightProperty));

                if (maybeRelation.HasValue())
                    relations.Add(maybeRelation.GetValue());
            }
        }

        private Dictionary<string, IObjectMember> GetMemberDictionary()
        {
            var members = new Dictionary<String, IObjectMember>();
            foreach (var member in objectMemberFactory.GetObjectMembers(typeof(RightType),includeFields))
                members.Add(GetMemberName(member), member);

            return members;
        }

        private String GetMemberName(IObjectMember member)
        {
            return caseInsensitive ? member.Name.ToLower() : member.Name;
        }

        public void Remove(Expression<Func<LeftType, object>> left, Expression<Func<RightType, object>> right)
        {
            relations.Remove(left,right);
        }
    }
}